#include "SceneNode.h"

#include <GL/gl.h>  // TODO: remove
#include <GL/glu.h>

namespace xEngine
{
    namespace PlatformIndependent
    {

        /**
         * Default constructor
         *
         */
        SceneNode::SceneNode() : Node(), objectsHashTable(NULL) {
        }

        /**
         * Constructor
         *
         * @param Node's key (integer)
         * Sets key to node an initiates it
         *
         */
        SceneNode::SceneNode(int key) : Node(key), objectsHashTable(NULL) {
        }

        /**
         * Constructor
         *
         * @param Node's relative position (Vector3)
         * Sets position to node and initiates it
         *
         */
        SceneNode::SceneNode(const Vector3 &pos) : Node(), position(pos), objectsHashTable(NULL) {
        }

        void SceneNode::setHash(SymTable<SceneNode*> *hash) {
            this->objectsHashTable = hash;

        }

        SymTable<SceneNode*> *SceneNode::getHash() const {
            return this->objectsHashTable;
        }

      /*  void SceneNode::printHash() {
            map<string, SceneNode*>::iterator it;

            for ( it = objectsHashTable->begin(); it != objectsHashTable->end(); it++ ) {
                cout<<"+----------------------+"<<endl;
                cout<<"| Name: " << (*it).first <<endl;
               // coutMM"| Id: " << this->
            }

            cout<<"+----------------------+"<<endl;
        }*/

        /**
         * Draw method
         *
         * Virtual
         * Draws this object and takes care that draw calls are called recursively over the tree
         *
         */
        void SceneNode::draw(double deltaTime) {
            // Draw this node
            // ...

            /*
            if (this->next != NULL) {
                cout<<" ";
                this->next->print();
            }
             */

            if (this->next) {

                // PUSH MATRIX?
               // glPushMatrix();
                ((SceneNode*)this->next)->draw(deltaTime);
             //   glPopMatrix();

            }

            // Draw children
            if (this->child) {
                // Draw the child node, relative to the parent
                // TODO: push matrix over GAL (Graphic Abstraction Layer)
                glPushMatrix();
                ((SceneNode*)this->child)->draw(deltaTime);
                glPopMatrix();
            }


        }

        /**
         * Update method
         *
         * Virtual
         * Updates this object and takes care that update calls are called recursively over the tree
         *
         *
         */
        void SceneNode::update(double deltaTime) {
            // Update this node
            // ...

            // Update children
            if (this->child) {
                ((SceneNode*)this->child)->update(deltaTime);
            }
        }

        /**
         * Animate method
         *
         * Virtual
         * Animates this object and takes care that animate calls are called recursively over the tree
         *
         */
        void SceneNode::animate(double deltaTime) {
            // Animate this node
            // ...

            // Animate children
                // Update children
            if (this->child) {
                ((SceneNode*)this->child)->animate(deltaTime);
            }

        }

         /**
         * Add child
         *
         * Adds child to this node
         *
         * @param  Node to add
         */
        void SceneNode::addChild(Node *node) {

            if ( this->objectsHashTable != NULL ) { // Is hash table present?
                ((SceneNode*)node)->setHash( this->objectsHashTable );
//                this->objectsHashTable->insert(pair<string, SceneNode*>( ((SceneNode*)node)->name,  (SceneNode*)node ) );
                this->objectsHashTable->insertSym( ((SceneNode*)node)->name,  (SceneNode*)node  );

            }

            Node::addChild(node);
        }

        /**
         * Add sibling
         *
         * Adds node next to this node (forms linked list)
         *
         * @param  Node to add
         */
        void SceneNode::addSibling(Node *node) {

            if ( this->objectsHashTable != NULL ) { // Is hash table present?
                ((SceneNode*)node)->setHash( this->objectsHashTable );
               // this->objectsHashTable->insert(pair<string, SceneNode*>( ((SceneNode*)node)->name,  (SceneNode*)node ) );
                this->objectsHashTable->insertSym( ((SceneNode*)node)->name,  (SceneNode*)node  );
            }

            Node::addSibling(node);
        }

        /**
         * Release
         *
         * Releases current node and it's children
         *
         */
        void SceneNode::release() {

            // Remove obj from hash table
//his->objectsHashTable->erase( this->objectsHashTable->find( this->name ) );

            Node::release();

        }
    }
}


